/***********************************************************************
 * Coord class
 * 
 * Implements two-dimensional coordinates
 *
 * Signature:
 *  public static Coord create (int x, int y);
 *  public static Coord origin ();
 *  public int xPos ();
 *  public int yPos ();
 *  public Coord move (int x, int y);
 *  public Coord add (Coord c);
 *  public boolean within (Coord c1, Coord c2);
 *  public double distance (Coord c);
 *  public int distanceInt (Coord c);
 *  public boolean equals (Coord c);
 *  public boolean equals (Object obj);
 *  public int hashCode ();
 *  public String toString ();
 ***********************************************************************/

import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONString;
import org.json.JSONStringer;

public class Coord implements JSONString {

  private int xpos;
  private int ypos;

  private Coord (int x, int y) {
    xpos = x;
    ypos = y;
  }

  public Coord() {
    // Used to create coords for calling fromJSON because java doesn't allow
    // static interface methods.  Not my fault.  I agree this is disgusting 
    // and ugly.
  }

  public static Coord create (int x, int y) {
    return new Coord(x,y);
  }

  public static Coord origin () {
    return create(0,0);
  }

  public int xPos () {
    return this.xpos;
  }

  public int yPos () {
    return this.ypos;
  }

  public Coord move (int x, int y) {
    return create(this.xPos()+x, this.yPos()+y);
  }

  public Coord add (Coord c) {
    return this.move (c.xPos(), c.yPos());
  }

  public boolean within (Coord c1, Coord c2) {
    return (c1.xPos() <= this.xPos() & 
	    c1.yPos() <= this.yPos() &
	    this.xPos() <= c2.xPos() &
	    this.yPos() <= c2.yPos());
  }

  public double distance (Coord c) {
    return Math.sqrt(Math.pow(this.xPos()-c.xPos(),2) + 
		     Math.pow(this.yPos()-c.yPos(),2));
  }

  public int distanceInt (Coord c) {
    Double v = new Double(Math.floor(this.distance(c)));
    return Math.round(v.floatValue());
  }

  public boolean equals (Coord c) {
    return (this.xPos()==c.xPos() && this.yPos()==c.yPos());
  }

    
  public boolean equals (Object obj) {
    return false;
  }

  public int hashCode () {
    return (this.xPos()+this.yPos())*(this.xPos()+this.yPos()+1)/2
      + this.yPos();
  }


  public String toString () {
    return "("+this.xPos()+","+this.yPos()+")";
  }

  
  public String jsonString() {
    return "[" + xpos + "," + ypos + "]";
  }
  
  public static Coord fromJSON(JSONObject json) {
    try {
      if(json.getString("className").equals("Coord")) {
        return Coord.create(json.getInt("x"), json.getInt("y"));
      } else {
        System.err.println("\"" + json.toString() + "\" does not represent a Coord.");
        throw new RuntimeException("Cannot parse JSON, it is not a Coord!");
      }
    } catch (JSONException e) {
      e.printStackTrace();
      throw new RuntimeException("Unrecoverable JSON error, see above stack trace");
    }
    
  }
  
  @Override
  public String toJSONString() {
    try {
      return new JSONStringer()
                        .object() 
                          .key("className")
                          .value("Coord")
                          .key("x")
                          .value(this.xPos())
                          .key("y")
                          .value(this.yPos())
                        .endObject().toString();
    } catch (JSONException e) {
      e.printStackTrace();
      throw new RuntimeException("Unrecoverable JSON error, see above stack trace.");
    }
  }
}
